﻿/*
 * Author:		shikezheng
 * Create date: 2011-06-15
 * Description:	EntityFramework泛型访问类（包含基本的增删改查操作),因为是通用类无法做到细化，
 *              如果要细化，请继承IDal接口实现所需要的类
 *              
 * Modify date：2011-06-30 添加批量删除代码。
 * */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic;
using Microsoft.Data.Extensions;

using YhmOA.IDAL;
using YhmOA.Common;
using System.Text.RegularExpressions;

namespace YhmOA.EFDAL
{
    public class TDal<T> : ITDal<T> where T : class
    {
        #region Private Field
        /// <summary>
        /// Entities
        /// </summary>
        private Entities entities;
        #endregion

        #region Constructor
        public TDal()
        {
            try
            {
                int len = typeof(T).Name.Split('_').Length;
                switch (len)
                {
                    case 1:
                        entities = new Entities(string.Empty, typeof(T).Name);
                        break;
                    case 2:
                        entities = new Entities(string.Empty, string.Format("{0}.{0}", typeof(T).Name.Split('_')[0]));
                        break;
                    case 3:
                        entities = new Entities(string.Empty, string.Format("{0}.{1}.{0}_{1}", typeof(T).Name.Split('_')[0], typeof(T).Name.Split('_')[1]));
                        break;
                    case 4:
                        entities = new Entities(string.Empty, string.Format("{0}.{1}.{2}.{0}_{1}_{2}", typeof(T).Name.Split('_')[0], typeof(T).Name.Split('_')[1], typeof(T).Name.Split('_')[2]));
                        break;
                    default:
                        entities = new Entities(typeof(T));
                        break;
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
            }
        }
        #endregion

        /// <summary>
        /// 取得实体集合
        /// </summary>
        /// <param name="conditions">条件</param>
        /// <param name="pageSize">页面大小</param>
        /// <param name="pageIndex">页码</param>
        /// <param name="orderByStr">排序</param>
        /// <param name="recCount">总数量</param>
        /// <returns>实体集合</returns>
        public List<T> GetList(string conditions, int pageSize, int pageIndex, string orderByStr, out int recCount)
        {
            List<T> list = new List<T>();
            recCount = 0;
            try
            {
                if (string.IsNullOrEmpty(orderByStr))
                {
                    orderByStr = "ID Desc";
                }
                var query = (from item in entities.CreateObjectSet<T>()
                             select item).OrderBy(orderByStr);
                if (!string.IsNullOrEmpty(conditions))
                {
                    query = query.Where(conditions);
                }
                
                recCount = query.Count();
                if (pageSize == 0 && pageIndex == 0)
                    list = query.ToList<T>();
                else
                    list = query.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList<T>();

            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                Log.info(string.Format("方法GetList，类型：{0}，参数：条件，{1}",typeof(T).Name, conditions));
            }
            return list;
        }

        /// <summary>
        /// 根据条件和排序取得单个实体
        /// </summary>
        /// <param name="conditions">条件</param>
        /// <param name="orderByStr">排序</param>
        /// <returns>单个实体</returns>
        public T GetSingle(string conditions, string orderByStr)
        {
            if (string.IsNullOrEmpty(orderByStr))
            {
                orderByStr = "ID Desc";
            }
            var query = (from item in entities.CreateObjectSet<T>()
                         select item).OrderBy(orderByStr);
            if (!string.IsNullOrEmpty(conditions))
            {
                query = query.Where(conditions);
            }
            return query.Take(1).SingleOrDefault();
        }

        /// <summary>
        /// 通用查询
        /// </summary>
        /// <param name="whereStr">查询条件</param>
        /// <param name="searchColumn">要查询的列</param>
        /// <param name="searchStr">搜索关键字</param>
        /// <param name="pageIndex">当前第几页</param>
        /// <param name="pageSize">每页的大小</param>
        /// <param name="orderColumn">排序的列</param>
        /// <param name="order">排序的方向</param>
        public List<T> SearchTable(
            String whereStr,
            String searchColumn,
            String searchStr,
            Int32 pageIndex,
            Int32 pageSize,
            String orderColumn,
            String order,
            out Int32 count)
        {
            {
                List<T> list = new List<T>();
                count = 0;
                try
                {
                    var query = entities.SearchTable<T>(typeof(T).Name,whereStr, searchColumn, searchStr, pageIndex, pageSize, orderColumn, order, out count);
                    list = query.ToList<T>();
                }
                catch (Exception ex)
                {
                    Log.Error(ex.Message);
                    Log.info(string.Format("方法SearchTable，类型：{0}，参数：条件，{1}", typeof(T).Name, whereStr));
                }
                return list;
            }
        }

        /// <summary>
        /// 根据ID得到实体
        /// </summary>
        /// <param name="id">id</param>
        /// <returns>实体</returns>
        public T GetModelByID(long id)
        {
            try
            {
                return (from item in entities.CreateObjectSet<T>()
                         select item).Where(String.Format("ID = {0}", id.ToString())).Single<T>();
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                return  (T)Activator.CreateInstance(typeof(T));
            }
        }

        /// <summary>
        /// 添加一个实体
        /// </summary>
        /// <param name="info">实体</param>
        /// <returns>操作是否成功</returns>
        public bool Add(T info)
        {
            bool isSucceed = false;
            try
            {
                entities.CreateObjectSet<T>().AddObject(info);
                isSucceed = entities.SaveChanges() > 0;
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                Log.info(string.Format("方法Add，类型：{0}", typeof(T).Name));
            }
            return isSucceed;
        }

        /// <summary>
        /// 添加实体集合
        /// </summary>
        /// <param name="list">实体集合</param>
        /// <returns>操作是否成功</returns>
        public bool AddRange(List<T> list)
        {
            bool isSucceed = false;
            try
            {
                foreach (var item in list)
                {
                    entities.CreateObjectSet<T>().AddObject(item);
                }
                isSucceed = entities.SaveChanges() > 0;
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                Log.info(string.Format("方法AddRange，类型：{0}", typeof(T).Name));
            }
            return isSucceed;
        }

        #region Update
        /// <summary>
        /// 更新一个实体
        /// </summary>
        /// <param name="info">实体</param>
        /// <returns>操作是否成功</returns>
        public bool Update(T info, long id)
        {
            bool isSucceed = false;
            try
            {
                var query = (from item in entities.CreateObjectSet<T>()
                             select item).Where(String.Format("ID = {0}", id.ToString()));
                info.ToModel(query.Single(), new string[] { "id" });
                isSucceed = entities.SaveChanges() > 0;
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                Log.info(string.Format("方法Update，类型：{0}，参数：id，{1}", typeof(T).Name, id));
            }
            return isSucceed;
        }

        /// <summary>
        /// 根据ID和SET子句键值对更新
        /// 方法：从Dynamiclinq中得到查询SQL语句，然后从SQL语句中生成更新SQL语句，然后ExecuteStoreCommand得到的更新SQL语句
        /// </summary>
        /// <param name="kv">KeyValuePair<string, string></param>
        /// <param name="id">条件</param>
        /// <returns>操作是否成功</returns>
        public bool Update(KeyValuePair<string, string> kv, long id)
        {
            return Update(kv, string.Format("id={0}", id.ToString()));
        }

        /// <summary>
        /// 根据条件和SET子句键值对更新
        /// 方法：从Dynamiclinq中得到查询SQL语句，然后从SQL语句中生成更新SQL语句，然后ExecuteStoreCommand得到的更新SQL语句
        /// </summary>
        /// <param name="kv">KeyValuePair<string, string></param>
        /// <param name="conditions">条件</param>
        /// <returns>操作是否成功</returns>
        public bool Update(KeyValuePair<string, string> kv, string conditions)
        {
            return Update(new List<KeyValuePair<string, string>>() { kv }, conditions);
        }

        /// <summary>
        /// 根据条件和SET子句键值对集合更新
        /// 方法：从Dynamiclinq中得到查询SQL语句，然后从SQL语句中生成更新SQL语句，然后ExecuteStoreCommand得到的更新SQL语句
        /// </summary>
        /// <param name="kvList">List<KeyValuePair<string, string>></param>
        /// <param name="conditions">条件</param>
        /// <returns>操作是否成功</returns>
        public bool Update(List<KeyValuePair<string, string>> kvList, string conditions)
        {
            return Update(formatUpdateStr(kvList), conditions);
        }

        /// <summary>
        /// 根据条件和SET子句更新
        /// 方法：从Dynamiclinq中得到查询SQL语句，然后从SQL语句中生成更新SQL语句，然后ExecuteStoreCommand得到的更新SQL语句
        /// </summary>
        /// <param name="kvStr">SET子句</param>
        /// <param name="conditions">条件</param>
        /// <returns>操作是否成功</returns>
        public bool Update(string kvStr, string conditions)
        {
            bool isSucceed = false;
            try
            {
                var query = (from item in entities.CreateObjectSet<T>()
                             select item).Where(conditions);

                string sqlStr = getUpdateStr(query.ToTraceString(), kvStr);
                if (!String.IsNullOrEmpty(sqlStr))
                {
                    isSucceed = entities.ExecuteStoreCommand(sqlStr) > 0;
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                Log.info(string.Format("方法Update，类型：{0}，参数：条件，{1}", typeof(T).Name, conditions));
            }
            return isSucceed;
        }
        #endregion
        #region Delete
        /// <summary>
        /// 删除一个实体
        /// </summary>
        /// <param name="id">id</param>
        /// <returns>操作是否成功</returns>
        public bool DeleteByID(long id)
        {
            return DeleteByIDS(id.ToString());
        }

        /// <summary>
        /// 根据ids批量删除实体
        /// </summary>
        /// <param name="ids">ids,ids格式：id_id_</param>
        /// <returns>操作是否成功</returns>
        public bool DeleteByIDS(string ids)
        {
            bool isSucceed = false;
            try
            {
                System.Text.StringBuilder sbIds = new System.Text.StringBuilder();
                foreach (var id in ids.Split('_'))
                {
                    sbIds.AppendFormat(" ID = {0}", id.ToString());
                    sbIds.Append(" OR");
                }
                string conditions = sbIds.ToString().Substring(0, sbIds.ToString().Length - 3);
                isSucceed = Delete(conditions);
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
            }
            return isSucceed;
        }

        /// <summary>
        /// 根据条件删除
        /// 方法：从Dynamiclinq中得到查询SQL语句，然后从SQL语句中生成删除SQL语句，然后ExecuteStoreCommand得到的删除SQL语句
        /// </summary>
        /// <param name="conditions">条件</param>
        /// <returns>操作是否成功</returns>
        public bool Delete(string conditions)
        {
            bool isSucceed = false;
            try
            {
                var query = (from item in entities.CreateObjectSet<T>()
                             select item).Where(conditions);

                string sqlStr = getDeleteStr(query.ToTraceString());
                if (!String.IsNullOrEmpty(sqlStr))
                {
                    isSucceed = entities.ExecuteStoreCommand(sqlStr) > 0;
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex.Message);
                Log.info(string.Format("方法Delete，类型：{0}，参数：条件，{1}", typeof(T).Name, conditions));
            }
            return isSucceed;
        }
        #endregion
       
        #region privateMethod
        /// <summary>
        /// 得到删除SQL语句
        /// </summary>
        /// <param name="sql">查询SQL语句</param>
        /// <returns>删除SQL语句</returns>
        private static string getDeleteStr(string sql)
        {
            string deleteSql = string.Empty;
            MatchCollection matches = Regex.Matches(sql, @"from\s*\[\s*dbo\s*\]\s*\.\s*\[\s*\w+\s*\]\s*(?<tableparam>(as\s*(?<tablepname>(\[\s*\w+\s*\]))))(\.|(\r)|(\n))*", RegexOptions.Multiline | RegexOptions.IgnoreCase);
            if (matches != null && matches.Count > 0)
            {
                Match match = matches[0];
                deleteSql = ("DELETE  " + match.Value.Replace(match.Groups["tableparam"].Value, "") +
                    sql.Substring(match.Index + match.Length)).Replace(match.Groups["tablepname"].Value + ".", " ");

            }
            return deleteSql;
        }

        /// <summary>
        /// 得到更新SQL语句
        /// </summary>
        /// <param name="sql">查询语句</param>
        /// <param name="kvStr">更新SET SQL语句</param>
        /// <returns>更新SQL语句</returns>
        private static string getUpdateStr(string sql,string kvStr)
        {
            string updateSql = string.Empty;
            MatchCollection matches = Regex.Matches(sql, @"\s*\[\s*dbo\s*\]\s*\.\s*\[\s*\w+\s*\]\s*(?<tableparam>(as\s*(?<tablepname>(\[\s*\w+\s*\]))))(\.|(\r)|(\n))*", RegexOptions.Multiline | RegexOptions.IgnoreCase);
            if (matches != null && matches.Count > 0)
            {
                Match match = matches[0];
                updateSql = ("UPDATE  " + match.Value.Replace(match.Groups["tableparam"].Value, "") +
                    (" SET " + kvStr) + 
                    sql.Substring(match.Index + match.Length)).Replace(match.Groups["tablepname"].Value + ".", " ");

            }

            return updateSql;
        }

        /// <summary>
        /// 将List<KeyValuePair<string, string>>转换为SQL语句
        /// </summary>
        /// <param name="kvList">List<KeyValuePair<string, string>></param>
        /// <returns>更新SQL语句</returns>
        private static string formatUpdateStr(List<KeyValuePair<string, string>> kvList)
        {
            System.Text.StringBuilder sb = new System.Text.StringBuilder();
            foreach (KeyValuePair<string, string> kv in kvList)
            {
                sb.AppendFormat("{0}='{1}' ", kv.Key, kv.Value);
            }
            return sb.ToString();
        }
        #endregion
    }
}
